package com.dny.asmtop;

import com.dny.asmtop.op.*;
import jdk.internal.org.objectweb.asm.Type;

import java.util.Arrays;
import java.util.List;

import static java.util.Arrays.asList;
import static jdk.internal.org.objectweb.asm.Type.getType;

/**
 * Created by jlutt on 2018-01-15.
 *
 * @author jlutt
 */
public final class CB {

  public CB() {
  }

  /**
   * 定义临时变量
   *
   * @param field
   * @return
   */
  public static Variable let(Command field) {
    return new CommandLet(field);
  }

  /**
   * 类型转换
   *
   * @param from 参数
   * @param type 转换类型
   * @return
   */
  public static Command cast(Command from, Class<?> type) {
    return cast(from, getType(type));
  }

  /**
   * 类型转换
   *
   * @param from 参数
   * @param type 转换类型
   * @return
   */
  public static Command cast(Command from, Type type) {
    return new CommandCast(from, type);
  }

  /**
   * 返回参数变量
   *
   * @param argument 参数索引，从0开始
   * @return
   */
  public static VarArg arg(int argument) {
    return new VarArg(argument);
  }

  /**
   * 返回owner的某字段变量
   *
   * @param owner
   * @param field
   * @return
   */
  public static VarField field(Command owner, String field) {
    return new VarField(owner, field);
  }

  public static VarStaticField fieldStatic(Class<?> owner, String field) {
    return new VarStaticField(owner, field);
  }

  /**
   * 对owner的字段赋值
   *
   * @param owner
   * @param fieldName
   * @param value
   * @return
   */
  public static Command set(Command owner, String fieldName, Command value) {
    return set(field(owner, fieldName), value);
  }

  /**
   * 赋值操作
   *
   * @param to   需要修改的变量
   * @param from 原始值
   * @return
   */
  public static Command set(StoreDef to, Command from) {
    return new CommandSet(to, from);
  }

  /**
   * 返回this当前实例
   *
   * @return
   */
  public static Command self() {
    return new CommandThis();
  }

  /**
   * 常量值
   *
   * @param value
   * @return
   */
  public static CommandValue value(Object value) {
    return new CommandValue(value);
  }

  /**
   * 构造对象实例
   * <p>
   * 注意构造对象如果是内部类，因为内部类默认构造函数是protected修饰，无参情况下无法进行实例化，
   * 其默认的public构造函数有一个上级类的参数
   * </p>
   *
   * @param type   对象类型
   * @param fields 构造函数参数
   * @return
   */
  public static CommandConstructor constructor(Class<?> type, Command... fields) {
    return new CommandConstructor(type, fields);
  }

  /**
   * false
   *
   * @return
   */
  public static PredicateDef alwaysFalse() {
    return new PredicateDefConst(false);
  }

  /**
   * true
   *
   * @return
   */
  public static PredicateDef alwaysTrue() {
    return new PredicateDefConst(true);
  }

  public static PredicateDef not(PredicateDef predicateDef) {
    return new PredicateDefNot(predicateDef);
  }

  /**
   * 比较参数
   *
   * @param op
   * @param left
   * @param right
   * @return
   */
  public static PredicateDefCmp cmp(PredicateDefCmp.Operation op, Command left, Command right) {
    return PredicateDefCmp.create(op, left, right);
  }

  /**
   * 参数相等
   *
   * @param left
   * @param right
   * @return
   */
  public static PredicateDefCmp eq(Command left, Command right) {
    return cmp(PredicateDefCmp.Operation.EQ, left, right);
  }

  /**
   * left>=right
   *
   * @param left
   * @param right
   * @return
   */
  public static PredicateDefCmp ge(Command left, Command right) {
    return cmp(PredicateDefCmp.Operation.GE, left, right);
  }

  /**
   * left <= right
   *
   * @param left
   * @param right
   * @return
   */
  public static PredicateDefCmp le(Command left, Command right) {
    return cmp(PredicateDefCmp.Operation.LE, left, right);
  }

  /**
   * left < right
   *
   * @param left
   * @param right
   * @return
   */
  public static PredicateDefCmp lt(Command left, Command right) {
    return cmp(PredicateDefCmp.Operation.LT, left, right);
  }

  /**
   * left > right
   *
   * @param left
   * @param right
   * @return
   */
  public static PredicateDefCmp gt(Command left, Command right) {
    return cmp(PredicateDefCmp.Operation.GT, left, right);
  }

  /**
   * left != right
   *
   * @param left
   * @param right
   * @return
   */
  public static PredicateDefCmp ne(Command left, Command right) {
    return cmp(PredicateDefCmp.Operation.NE, left, right);
  }

  /**
   * 多条件and
   *
   * @param predicateDefs
   * @return
   */
  public static PredicateDefAnd and(List<PredicateDef> predicateDefs) {
    return PredicateDefAnd.create(predicateDefs);
  }

  /**
   * 多条件and
   *
   * @param predicateDefs
   * @return
   */
  public static PredicateDefAnd and(PredicateDef... predicateDefs) {
    return and(asList(predicateDefs));
  }

  /**
   * 多条件or
   *
   * @param predicateDefs
   * @return
   */
  public static PredicateDefOr or(List<PredicateDef> predicateDefs) {
    return PredicateDefOr.create(predicateDefs);
  }

  /**
   * 多条件or
   *
   * @param predicateDefs
   * @return
   */
  public static PredicateDefOr or(PredicateDef... predicateDefs) {
    return or(asList(predicateDefs));
  }

  /**
   * if...else
   *
   * @param condition
   * @param left
   * @param right
   * @return
   */
  public static Command ifThenElse(PredicateDef condition, Command left, Command right) {
    return new CommandIf(condition, left, right);
  }

  /**
   * field是否为空
   *
   * @param field
   * @return
   */
  public static PredicateDef isNull(Command field) {
    return new CommandCmpNull(field);
  }

  public static PredicateDef isNotNull(Command field) {
    return new CommandCmpNotNull(field);
  }

  public static Command nullRef(Class<?> type) {
    return new CommandNull(type);
  }

  public static Command nullRef(Type type) {
    return new CommandNull(type);
  }

  public static Command call(Command owner, String methodName, Command... arguments) {
    return new CommandCall(owner, methodName, arguments);
  }

  /**
   * 调用父类指定的方法
   *
   * @param methodName
   * @param arguments
   * @return
   */
  public static Command callSuper(String methodName, Command... arguments) {
    return new CommandCallSuper(methodName, arguments);
  }

  /**
   * 在继承方法中调用父类对应的方法
   *
   * @return
   */
  public static Command callSuper() {
    return new CommandCallSuper();
  }

  public static Command callStatic(Class<?> owner, String method, Command... arguments) {
    return new CommandCallStatic(owner, method, arguments);
  }

  public static Command callStaticSelf(String method, Command... arguments) {
    return new CommandCallStaticSelf(method, arguments);
  }

  public static Class<?> unifyArithmeticTypes(Class<?>... types) {
    return CommandArithmetic.unifyArithmeticTypes(types);
  }

  public static Class<?> unifyArithmeticTypes(List<Class<?>> types) {
    return CommandArithmetic.unifyArithmeticTypes(types.toArray(new Class[types.size()]));
  }

  /**
   * 四则运算
   *
   * @param op
   * @param left
   * @param right
   * @return
   */
  public static CommandArithmetic arithmeticOp(CommandArithmetic.Operation op, Command left, Command right) {
    return new CommandArithmetic(op, left, right);
  }

  /**
   * add
   *
   * @param left
   * @param right
   * @return
   */
  public static CommandArithmetic add(Command left, Command right) {
    return new CommandArithmetic(CommandArithmetic.Operation.ADD, left, right);
  }

  public static CommandArithmetic inc(Command value) {
    return new CommandArithmetic(CommandArithmetic.Operation.ADD, value, value(1));
  }

  public static CommandArithmetic sub(Command left, Command right) {
    return new CommandArithmetic(CommandArithmetic.Operation.SUB, left, right);
  }

  public static CommandArithmetic dec(Command value) {
    return new CommandArithmetic(CommandArithmetic.Operation.SUB, value, value(1));
  }

  public static CommandArithmetic mul(Command left, Command right) {
    return new CommandArithmetic(CommandArithmetic.Operation.MUL, left, right);
  }

  public static CommandArithmetic div(Command left, Command right) {
    return new CommandArithmetic(CommandArithmetic.Operation.DIV, left, right);
  }

  public static CommandArithmetic rem(Command left, Command right) {
    return new CommandArithmetic(CommandArithmetic.Operation.REM, left, right);
  }

  /**
   * for i 操作
   *
   * @param start
   * @param length
   * @param forVar
   * @return
   */
  public static Command fori(Command start, Command length, ForVar forVar) {
    return new CommandFor(start, length, forVar);
  }

  /**
   * for i 操作，起始位0
   *
   * @param length
   * @param forVar
   * @return
   */
  public static Command fori(Command length, ForVar forVar) {
    return new CommandFor(length, forVar);
  }

  /**
   * map foreach操作
   *
   * @param map
   * @param forKey
   * @param forValue
   * @return
   */
  public static Command mapForEach(Command map, ForVar forKey, ForVar forValue) {
    return new CommandMapForEach(map, forKey, forValue);
  }

  /**
   * 数组，集合foreach操作
   *
   * @param collection
   * @param forCollection
   * @return
   */
  public static Command forEach(Command collection, ForVar forCollection) {
    return new CommandCollectionForEach(collection, forCollection);
  }

  /**
   * 数组，集合foreach操作
   *
   * @param collection
   * @param type
   * @param forCollection
   * @return
   */
  public static Command forEach(Command collection, Class<?> type, ForVar forCollection) {
    return new CommandCollectionForEach(collection, type, forCollection);
  }

  /**
   * 获取数组或集合对象的长度
   *
   * @param argument
   * @return
   */
  public static Command length(Command argument) {
    return new CommandLength(argument);
  }

  /**
   * 新建数组
   *
   * @param type
   * @param length
   * @return
   */
  public static Command newArray(Class<?> type, Command length) {
    return new CommandArrayNew(type, length);
  }

  /**
   * 获取数组元素
   *
   * @param array
   * @param position
   * @return
   */
  public static Command getArrayItem(Command array, Command position) {
    return new CommandArrayGet(array, position);
  }

  /**
   * 集合对象简化操作set
   *
   * @param list
   * @param position
   * @param value
   * @return
   */
  public static Command setListItem(Command list, Command position, Command value) {
    return call(list, "set", position, value);
  }

  /**
   * 集合对象简化操作get
   *
   * @param list
   * @param position
   * @return
   */
  public static Command getListItem(Command list, Command position) {
    return call(list, "get", position);
  }

  /**
   * 集合对象简化操作add
   *
   * @param list
   * @param value
   * @return
   */
  public static Command addListItem(Command list, Command value) {
    return call(list, "add", value);
  }

  /**
   * 数组元素赋值
   *
   * @param array
   * @param position
   * @param item
   * @return
   */
  public static Command setArrayItem(Command array, Command position, Command item) {
    return new CommandArraySet(array, position, item);
  }

  public static Command voidReturn() {
    return CommandVoid.instance;
  }

  /**
   * 构造操作顺序队列
   *
   * @param commands
   * @return
   */
  public static Command sequence(List<Command> commands) {
    return CommandSequence.create(commands);
  }

  /**
   * 构造操作顺序队列
   *
   * @param commands
   * @return
   */
  public static Command sequence(Command... commands) {
    return CommandSequence.create(Arrays.asList(commands));
  }
}
